home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / drdobbs.zip / UC993.TXT < prev    next >
Text File  |  1993-10-08  |  16KB  |  388 lines

  1. _UNDOCUMENTED CORNER_
  2. edited by Andrew Schulman
  3. written by Pete Davis
  4.  
  5. [LISTING ONE]
  6.  
  7. /* WHSTRUCT.H--Windows Help File Internal Records--Pete Davis and Ron Burk, 
  8.    June 1993. See "Undocumented Corner," DDJ, September 1993  */
  9.  
  10. typedef unsigned long   DWORD;
  11. typedef unsigned int    WORD;
  12. typedef unsigned char   BYTE;
  13.  
  14. #define HELP_MAGIC      0x00035F3FL
  15.  
  16. /* Help file Header record */
  17. typedef struct HELPHEADER {
  18.     DWORD   MagicNumber;      /* 0x00035F3F                */
  19.     long    WHIFS;            /* File offset of WHIFS header   */
  20.     long    Negative1;
  21.     long    FileSize;         /* Size of entire .HLP File  */
  22. }   HELPHEADER;
  23. /* File Header for WHIFS files */
  24. typedef struct FILEHEADER {
  25.     long    FilePlusHeader;  /* File size including this header */
  26.     long    FileSize;        /* File size not including header  */
  27.     char    TermNull;
  28. }   FILEHEADER;
  29. /* Help Directory BTREE */
  30. typedef struct WHIFSBTREEHEADER {
  31.     char    Magic[18];      /* Not exactly magic for some .MVB files   */
  32.     char    Garbage[13];
  33.     int     MustBeZero;     /* Probably shows up when Help > ~40 megs  */
  34.     int     NSplits;        /* Number of page split Btree has suffered */
  35.     int     RootPage;       /* Page # of root page                     */
  36.     int     MustBeNegOne;   /* Probably shows up when B-Tree is HUGE!! */
  37.     int     TotalPages;     /* total # to 2Kb pages in Btree           */
  38.     int     NLevels;        /* Number of levels in this Btree          */
  39.     DWORD   TotalWHIFSEntries;
  40. }   WHIFSBTREEHEADER;
  41. /* Modified B-Tree Node header to handle a pointer to the page */
  42. typedef struct BTREENODEHEADER {
  43.     WORD    Signature;      /* Signature word            */
  44.     int     NEntries;       /* Number of entries         */
  45.     int     PreviousPage;   /* Index of Previous Page    */
  46.     int     NextPage;       /* Index of Next Page        */
  47.     char    *BTData;        /* Pointer to B-Tree's data  */    
  48. }   BTREENODEHEADER;
  49. /* Modified B-Tree Index header to handle a pointer to the page */
  50. typedef struct BTREEINDEXHEADER {
  51.     WORD    Signature;      /* Signature word            */
  52.     int     NEntries;       /* Number of entries in node */
  53.     char    *IdxData;
  54. }   BTREEINDEXHEADER;
  55. /* Phrase header for uncompressed |Phrases file */
  56. typedef struct PHRASEHDR    {
  57.     int     NumPhrases;   /* Number of phrases in table                    */
  58.     WORD    OneHundred;   /* 0x0100                                        */
  59. } PHRASEHDR;
  60. /* Phrase header for compressed |Phrases file */
  61. typedef struct ALTPHRASEHDR    {
  62.     int     NumPhrases;   /* Number of phrases in table                    */
  63.     WORD    OneHundred;   /* 0x0100                                        */
  64.     long    PhrasesSize;  /* Amount of space uncompressed phrases requires */
  65. } ALTPHRASEHDR;
  66. /* Flags for |SYSTEM header Flags field below:  Unfortunately, none of these
  67.    flags are particularly solid. The 0x0004 works MOST of the time. Another
  68.    flag, 0x0008, appears both in Win32 .HLP files, and in files with Phrase
  69.    compression but without LZ77 compression. */
  70. #define NO_COMPRESSION_310      0x0000
  71. #define COMPRESSION_310         0x0004
  72. #define SYSFLAG_300             0x000A
  73. /* Header for |SYSTEM file */
  74. typedef struct SYSTEMHEADER {
  75.     BYTE    Magic;     /* 0x6C                  */
  76.     BYTE    Version;   /* Version #             */
  77.     BYTE    Revision;  /* Revision code         */
  78.     BYTE    Always0;   /* Unknown               */
  79.     WORD    Always1;   /* Always 0x0001         */
  80.     DWORD   GenDate;   /* Date/Time that the help file was generated    */
  81.     WORD    Flags;     /* Values seen: 0x0000 0x0004, 0x0008, 0x000A    */
  82.     } SYSTEMHEADER;
  83. /* Types for SYSTEMREC RecordType below:  note that other record types,
  84.    such as 0x0A, 0x0B, 0x0C, 0x0D, shown up in the large .MVB files used
  85.    by the MSDN CD-ROM and Cinemania products. */
  86. #define HPJ_TITLE       0x0001      /* Title from .HPJ file            */
  87. #define HPJ_COPYRIGHT   0x0002      /* Copyright notice from .HPJ file */
  88. #define HPJ_CONTENTS    0x0003      /* Contents=  from .HPJ            */
  89. #define MACRO_DATA      0x0004      /* RData = 4 nulls if no macros    */
  90. #define ICON_DATA       0x0005      /* Data for Icon                   */
  91. #define HPJ_SECWINDOWS  0x0006      /* Secondary window info in .HPJ   */
  92. #define HPJ_CITATION    0x0008      /* Citation= under [OPTIONS]       */
  93. /* Secondary Window Record following type 0x0006 System Record */
  94. typedef struct SECWINDOW {
  95.     WORD    Flags;          /* Flags (See Below)        */
  96.     BYTE    Type[10];       /* Type of window           */
  97.     BYTE    Name[9];        /* Window name              */
  98.     BYTE    Caption[51];    /* Caption for window       */
  99.     WORD    X;              /* X coordinate to start at */
  100.     WORD    Y;              /* Y coordinate to start at */
  101.     WORD    Width;          /* Width to create for      */
  102.     WORD    Height;         /* Height to create for     */
  103.     WORD    Maximize;       /* Maximize flag            */
  104.     BYTE    Rgb[3];         /* RGB for background       */
  105.     BYTE    Unknown1;       /* No known use             */
  106.     BYTE    RgbNsr[3];      /* RGB for non scrollable region */
  107.     BYTE    Unknown2;       /* No known use             */
  108. } SECWINDOW;
  109. /* Values for Secondary Window Flags */
  110. #define WSYSFLAG_TYPE       0x0001  /* Type is valid        */
  111. #define WSYSFLAG_NAME       0x0002  /* Name is valid        */
  112. #define WSYSFLAG_CAPTION    0x0004  /* Ccaption is valid    */
  113. #define WSYSFLAG_X          0x0008  /* X    is valid        */
  114. #define WSYSFLAG_Y          0x0010  /* Y    is valid        */
  115. #define WSYSFLAG_WIDTH      0x0020  /* Width    is valid    */
  116. #define WSYSFLAG_HEIGHT     0x0040  /* Height   is valid    */
  117. #define WSYSFLAG_MAXIMIZE   0x0080  /* Maximize is valid    */
  118. #define WSYSFLAG_RGB        0x0100  /* Rgb  is valid        */
  119. #define WSYSFLAG_RGBNSR     0x0200  /* RgbNsr   is valid    */
  120. #define WSYSFLAG_TOP        0x0400  /* On top was set in HPJ file */
  121. /* Help Compiler 3.1 System record. Multiple records possible */
  122. typedef struct SYSTEMREC {
  123.     WORD    RecordType;   /* Type of Data in record      */
  124.     WORD    DataSize;     /* Size of RData               */
  125.     char   *RData;        /* Raw data (Icon, title, etc) */
  126.     } SYSTEMREC;
  127. /* Header for |TOMAP file */
  128. typedef struct TOMAPHEADER {
  129.     long    IndexTopic;   /* Index topic for help file */
  130.     long    Reserved[15];
  131.     int     ToMapLen;     /* Number of topic pointers  */
  132.     long    *TopicPtr;    /* Pointer to all the topics */
  133.     } TOMAPHEADER;
  134.  
  135.  
  136. [LISTING TWO]
  137.  
  138. /* HELPDIR.C -- List all internal files with a Windows .HLP file. 
  139.    WHIFS = Windows Help Internal File System -- Pete Davis, June 1993
  140.    bcc helpdir.c
  141.    See "Undocumented Corner," DDJ, September 1993 */
  142. #pragma pack(1)
  143. #include <conio.h>
  144. #include <string.h>
  145. #include <stdio.h>
  146. #include <stdlib.h>
  147. #include "whstruct.h"
  148.  
  149. #define PAGE_SIZE       1024L        /* 1k pages -- must be long! */
  150.  
  151. void fail(const char *s) { puts(s); exit(1); }
  152.  
  153. int main(int argc, char *argv[]) {
  154.    HELPHEADER         HelpHdr;
  155.    WHIFSBTREEHEADER   WHIFSHdr;
  156.    BTREENODEHEADER    WHIFSNode;
  157.    int                file, aPage, c;
  158.    long               WHIFSStart, FileOffset;
  159.    FILE               *HelpFile;
  160.    
  161.    if ((HelpFile=fopen(argv[1], "rb")) == NULL)
  162.        fail("can't open file");
  163.    /* Get Help header, go to WHIFS and get WHIFS Header */
  164.    fread(&HelpHdr, sizeof(HelpHdr), 1, HelpFile);
  165.    if (HelpHdr.MagicNumber != HELP_MAGIC)
  166.        fail("not a Windows help file");
  167.    fseek(HelpFile, HelpHdr.WHIFS, SEEK_SET);
  168.    fread(&WHIFSHdr, sizeof(WHIFSHdr), 1, HelpFile);
  169.    /* WHIFS starts after the WHIFSHdr */
  170.    WHIFSStart = HelpHdr.WHIFS + sizeof(WHIFSHdr);
  171.    file=1;
  172.    /* Goto WHIFS Root */
  173.    fseek(HelpFile, WHIFSStart + (PAGE_SIZE * WHIFSHdr.RootPage), SEEK_SET);
  174.    /* Find the first leaf node */
  175.    while (file < WHIFSHdr.NLevels) {
  176.        /* if it's not a leaf, we don't need last 2 fields */
  177.        fread(&WHIFSNode, 4, 1, HelpFile);
  178.        /* Find page pointer to first node in index */
  179.        fread(&aPage, sizeof(int), 1, HelpFile);
  180.        fseek(HelpFile, WHIFSStart + (PAGE_SIZE * aPage), SEEK_SET);
  181.        file++;
  182.    }
  183. #ifdef DO_MACROS
  184. {
  185.     extern void do_macros(FILE *HelpFile, long WHIFSStart);
  186.     do_macros(HelpFile, WHIFSStart);
  187. }
  188. #else
  189.    /* Go through linked list of leaf nodes */
  190.    for (;;) {
  191.        if (! fread(&WHIFSNode, sizeof(WHIFSNode)-2, 1, HelpFile))
  192.            break;
  193.        /* List all entries in node */
  194.        for (file = 1; file <= WHIFSNode.NEntries; file ++) {
  195.           while (c = fgetc(HelpFile))
  196.                putchar(c);
  197.           fread(&FileOffset, sizeof(FileOffset), 1, HelpFile);
  198.           printf("  \t0x%08lX\n", FileOffset);
  199.        }
  200.        if (WHIFSNode.NextPage == -1)
  201.           break;
  202.       else
  203.           fseek(HelpFile,WHIFSStart+(WHIFSNode.NextPage*PAGE_SIZE),SEEK_SET);
  204.    } 
  205. #endif
  206.    return 1;
  207. }
  208.  
  209.  
  210. [LISTING THREE]
  211.  
  212. /* WHMACROS.C -- Get macros from a .HLP file. Used by HELPDIR.C if #define 
  213.    DO_MACROS -- Pete Davis and Andrew Schulman, 
  214.    bcc -DDO_MACROS whmacros.c helpdir.c
  215.    See "Undocumented Corner," DDJ, September 1993 */
  216.  
  217. #pragma pack(1)
  218. #include <conio.h>
  219. #include <string.h>
  220. #include <stdio.h>
  221. #include <stdlib.h>
  222. #include "whstruct.h"
  223.  
  224. extern void fail(const char *s);
  225.  
  226. #define PAGE_SIZE       1024L        /* 1k pages -- must be long! */
  227.  
  228. void do_macros(FILE *HelpFile, long WHIFSStart)
  229. {
  230.    BTREENODEHEADER  WHIFSNode;
  231.    SYSTEMHEADER     SystemHdr;
  232.    SYSTEMREC        SystemRec;
  233.    FILEHEADER       FileHdr;
  234.    long             SystemOffset=0, FileOffset, FileStart;
  235.    char             filename[20], *data;
  236.    int              *Offsets;
  237.    int              c, i, file, txt;
  238.    /* Find the System file. */
  239.    do {
  240.        fread(&WHIFSNode, sizeof(WHIFSNode) - 2, 1, HelpFile);
  241.        /* Search all entries in node */
  242.        for (file = 1; file <= WHIFSNode.NEntries; file ++) {
  243.           i = 0;
  244.           while ( c = fgetc(HelpFile) )
  245.                 filename[i++]=c;
  246.           filename[i] = 0;
  247.           fread(&FileOffset, sizeof(FileOffset), 1, HelpFile);
  248.           if (strcmp(filename, "|SYSTEM") == 0) {
  249.               SystemOffset = FileOffset;
  250.               break;
  251.           }
  252.        }
  253.        if (WHIFSNode.NextPage != -1)
  254.           fseek(HelpFile, WHIFSStart + (WHIFSNode.NextPage * PAGE_SIZE), 
  255.               SEEK_SET);
  256.    } while (WHIFSNode.NextPage != -1);
  257.     if (! SystemOffset)
  258.         fail("Can't locate |SYSTEM file");
  259.    /* Get System header */
  260.    fseek(HelpFile, SystemOffset, SEEK_SET);
  261.    fread(&FileHdr, sizeof(FileHdr), 1, HelpFile);
  262.    fread(&SystemHdr, sizeof(SystemHdr), 1, HelpFile);
  263.  
  264.    FileStart = SystemOffset + sizeof(FileHdr) + sizeof(SystemHdr);
  265.    FileOffset = 0;
  266.    while (FileOffset < FileHdr.FileSize)    {
  267.        fseek(HelpFile, FileStart + FileOffset, SEEK_SET);
  268.        fread(&SystemRec, sizeof(SystemRec)-1, 1, HelpFile);
  269.        FileOffset += (sizeof(SystemRec) + SystemRec.DataSize - 1);
  270.        if (SystemRec.RecordType == MACRO_DATA)  {
  271.            if (! (data = (char *) malloc(SystemRec.DataSize+1))) 
  272.                fail("insufficient memory");
  273.            fread(data, SystemRec.DataSize, 1, HelpFile);
  274.            data[SystemRec.DataSize] = '\0';
  275.            printf("%s\n\n", data);
  276.            free(data);
  277.        }
  278.    }
  279. }
  280.  
  281.  
  282.  
  283.  
  284. Figure 1: Annotated hex dump of portions of a .HLP file. (a) All .HLP files 
  285. start with a HELPHEADER. The first long is the .HLP magic number (0x035F3F). 
  286. The next long is the file offset of the WHIFS header (in Figure 1(b), that's 
  287. 0x041F); (b) the WHIFS starts off with a WHIFSBTREEHEADER, immediately 
  288. followed by the WHIFS directory, which contains null-terminated file names
  289. followed by the individual WHIFS file's offset within the larger .HLP
  290. file. Here, bag.ini is at offset 0x10, |CONTEXT is at 0x0362B3, and
  291. |CTXOMAP is at 0x032B02; (c) each internal file begins with FILEHEADER 
  292. structure, which specifies the file's size both with and without the header, 
  293. followed by a 0. Here, bag.ini is 0x040F bytes with the header, and 0x0F06 
  294. without. The file data itself (evidentally, some kind of initialization file)
  295. starts immediately after the header.
  296.  
  297. (a)
  298.  
  299. D:\MIPS>dump msmail32.hlp -bytes 8 
  300. 00000000 | 3F 5F 03 00 1F 04 00 00                         | ?_......
  301.  
  302. (b)
  303.  
  304. D:\MIPS>dump msmail32.hlp -offset 0x041f 
  305. 0000041f | 2F 04 00 00 26 04 00 00 04 3B 29 02 04 00 04 7A | /...&....;)....z
  306. 0000042f | 34 00 00 43 3A 5C 7E 68 63 35 00 09 02 62 6D 00 | 4..C:\~hc5...bm.
  307. 0000043f | 00 00 00 00 00 FF FF 01 00 01 00 1E 00 00 00 C1 | ................
  308. 0000044f | 02 1E 00 FF FF FF FF 62 61 67 2E 69 6E 69 00 10 | .......bag.ini..
  309. 0000045f | 00 00 00 7C 43 4F 4E 54 45 58 54 00 B3 62 03 00 | ...|CONTEXT..b..
  310. 0000046f | 7C 43 54 58 4F 4D 41 50 00 02 2B 03 00 7C 46 4F | |CTXOMAP..+..|FO
  311. ; ... etc. ...
  312.  
  313. (c)
  314.  
  315. D:\MIPS>dump d:\mips\msmail32.hlp -offset 0x10
  316. 00000010 | 0F 04 00 00 06 04 00 00 00 0D 0A 5B 62 61 67 2E | ...........[bag.
  317. 00000020 | 69 6E 69 5D 0D 0A 67 72 6F 75 70 63 6F 75 6E 74 | ini]..groupcount
  318. 00000030 | 3D 31 34 0D 0A 67 72 6F 75 70 31 3D 42 61 63 6B | =14..group1=Back
  319. 00000040 | 75 70 0D 0A 67 72 6F 75 70 32 3D 43 6C 69 70 62 | up..group2=Clipb
  320. ; ... etc. ...
  321.  
  322.  
  323.  
  324. Figure 2: HELPDIR output for the .HLP file hex dumped in Figure 1.
  325.  
  326. D:\MIPS>c:\ddj\helpdir msmail32.hlp
  327. bag.ini                 0x00000010
  328. |CONTEXT                0x000362B3
  329. |CTXOMAP                0x00032B02
  330. |FONT                   0x000327D2
  331. |KWBTREE                0x00033255
  332. |KWDATA                 0x00032ED5
  333. |KWMAP                  0x0003323E
  334. |SYSTEM                 0x0000084E
  335. |TOPIC                  0x00000A53
  336. |TTLBTREE               0x00034A84
  337. |bm0                    0x00037AE2
  338. ; ... etc. ...
  339.  
  340.  
  341. Figure 3: Selected macros in Microsoft Cinemania and the MSDN
  342. CD-ROM, as displayed by WHMACROS.
  343.  
  344. C:\DDJ>dir d:\content\*.mvb
  345. CINMANIA MVB 139104719 08-18-92  12:00a
  346.  
  347. C:\DDJ>whmacros d:\content\cinmania.mvb
  348. RegisterRoutine("ftui","InitRoutines","SU")
  349. RegisterRoutine("ftui","ExecFullTextSearch","USSS")
  350. ; ...
  351. InitRoutines(qchPath,1)
  352. ; ...
  353. CreateButton("ftSearch", "&Search", \
  354.     "ExecFullTextSearch(hwndApp, qchPath, `', `')")
  355. ; ...
  356.  
  357. C:\DDJ>dir d:\*.mvb
  358. MSDNCD   MVB 270353088 04-05-93   5:58p
  359.  
  360. C:\DDJ>whmacros d:\msdncd.mvb
  361. RegisterRoutine("msdncd", "Navigator", "USS")
  362. Navigator(hwndApp, "Load", qchPath)
  363. ; ...
  364. CreateButton("btn_prv","<<I&ndex","Navigator(hwndApp,\"Prev\",\"\")")
  365. CreateButton("btn_nxt","Inde&x>>","Navigator(hwndApp,\"Next\",\"\")")
  366.  
  367.  
  368.  
  369. Table 1: WinHelp internal files
  370.  
  371. Function        Description
  372.  
  373. bmx         Bitmap files, numbered (bm0, bm24, bm12, and so on. Do not 
  374.             start with a |)
  375. |CONTEXT    Context topic table
  376. |CTXOMAP    Context mapping to topics
  377. |FONT       Fonts available to help file
  378. |KWBTREE    Keyword B-tree file
  379. |KWDATA     Keyword mappings to topic file
  380. |KWMAP      Map into the KWBTREE for quick access
  381. |Phrases    A list of phrases used for compression of the |TOPIC file
  382. |SYSTEM     Contains mostly information from .HPJ file
  383. |TOMAP      List of pointers to topics
  384. |TOPIC      Contains the actual help text (usually compressed)
  385. |TTLBTREE   Topic titles B-tree
  386. baggage     Appears under the filename exactly as specified in help project
  387.  
  388.